
#include "ltdb.h"
#include "ltfile.h"
#include "pub/runlog.h"


ltbool
lt_file_extend(
    lt_file_t   os_file,
    uint64      offset,
    uint64      len
)
{
    DWORD    offset_low;
    DWORD    offset_high;
    DWORD    offset_new;

    lt_assert(os_file != LT_INVALID_HANDLE);
    offset += len;

    offset_low  = (uint32)(offset & 0xFFFFFFFF);
    offset_high = (uint32)((offset >> 32) & 0xFFFFFFFF);

    offset_new = SetFilePointer(os_file, offset_low, &offset_high, FILE_BEGIN);
    if (offset_new == 0xFFFFFFFF &&
        offset_low != 0xFFFFFFFF &&
        GetLastError() != NO_ERROR)
    {
        LT_ERROR("lt_file_extend error! handle: 0x%x, code: %d, offset: %I64d", os_file, GetLastError(), offset);

        offset_low = GetLastError();
        return LT_FALSE;
    }

    return SetEndOfFile(os_file);
}

lt_file_t
lt_file_create(
    schar*  path               
)
{
    lt_file_t   file;

    file = CreateFile(path,
                    GENERIC_READ | GENERIC_WRITE,
                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                    NULL, 
                    CREATE_NEW,
                    FILE_FLAG_RANDOM_ACCESS, //FILE_FLAG_NO_BUFFERING,
                    NULL);

    if (file == INVALID_HANDLE_VALUE)
    {
        LT_ERROR("lt_file_create error! path: %s, code: %d", path, GetLastError());

        return LT_INVALID_HANDLE;
    }
    else
    {
        if (GetFileType(file) != FILE_TYPE_DISK)
        {
            LT_ERROR("os_file_create_ex type error! path: %s", path);

            CloseHandle(file);
            
            return LT_INVALID_HANDLE;
        }
    }

    return file;
}


ltbool
lt_file_flush(
    lt_file_t   file  
)
{
    BOOL    ret;

    ret = FlushFileBuffers(file);

    if (ret) 
    {
        return LT_TRUE ;
    }
    else
    {
        LT_ERROR("lt_file_flush error! handle: 0x%x, code: %d", file, GetLastError());

        return LT_FALSE;
    }

}

ltbool
lt_file_trunc(
        lt_file_t   file,
        uint64      offset
)
{
    uint32  offset_low;
    uint32  offset_high;
    BOOL    flag;

    offset_low  = (uint32)(offset & 0xFFFFFFFF);
    offset_high = (uint32)((offset >> 32) & 0xFFFFFFFF);

    offset_low = SetFilePointer(file, offset_low, &offset_high, FILE_BEGIN);
    if (offset_low == 0xFFFFFFFF &&
        GetLastError() != NO_ERROR)
        return LT_FALSE;

    flag = SetEndOfFile(file);

    if (!flag)
        return LT_FALSE;
    
    lt_file_flush(file);

    return LT_TRUE;

}


ltbool
lt_file_read_offset(
    lt_file_t   file,
    uint64      offset, 
    byte*       buffer, 
    uint32      bytes_to_read 
)
{

    DWORD   offset_low;
    DWORD   offset_high;
    DWORD   offset_new;
    uint32  bytes_read;

    offset_low  = (uint32)(offset & 0xFFFFFFFF);
    offset_high = (uint32)((offset >> 32) & 0xFFFFFFFF);

    offset_new = SetFilePointer(file, offset_low, &offset_high, FILE_BEGIN);
    if (offset_new == 0xFFFFFFFF &&
        offset_low != 0xFFFFFFFF &&
        GetLastError() != NO_ERROR)
    {
        LT_ERROR("lt_file_read_offset error! handle: 0x%x, code: %d, offset: %I64d", file, GetLastError(), offset);
        return LT_FALSE;
    }

    if (ReadFile(file, buffer, bytes_to_read, &bytes_read, NULL))
    {
        if (bytes_read == bytes_to_read)
            return LT_TRUE;
        else
        {
            LT_ERROR("lt_file_read_offset error! handle: 0x%x, code: %d", file, GetLastError());
            return LT_FALSE;
        }
    }
    else
    {
        LT_ERROR("lt_file_read_offset error! handle: 0x%x, code: %d", file, GetLastError());
        return LT_FALSE;
    }
}

ltbool
lt_file_write_offset(
    lt_file_t   file,
    uint64      offset,
    byte*       buffer,
    uint32      bytes_to_write
)
{
    DWORD   offset_low;
    DWORD   offset_high;
    DWORD   offset_new;

    uint32  bytes_written;

    offset_low  = (uint32)(offset & 0xFFFFFFFF);
    offset_high = (uint32)((offset >> 32) & 0xFFFFFFFF);

    offset_new = SetFilePointer(file, offset_low, &offset_high, FILE_BEGIN);
    if (offset_new == 0xFFFFFFFF &&
        offset_low != 0xFFFFFFFF &&
        GetLastError() != NO_ERROR)
    {
        LT_ERROR("lt_file_write_offset error! handle: 0x%x, code: %d, offset: %I64d", file, GetLastError(), offset);
        bytes_to_write = GetLastError();
        return LT_FALSE;
    }

     if (WriteFile(file, buffer, bytes_to_write, &bytes_written, NULL))
         return LT_TRUE;
     else
     {
        LT_ERROR("lt_file_write_offset error! handle: %d, code: %d", file, GetLastError());
        return LT_FALSE;
     }
}

